package sameClasses;

import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.KeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import org.spongycastle.util.encoders.Base64;

public class Crypter {

	public Crypter() {
	}

	private static SecretKey buildSecret(char[] password, byte[] salt) {
		SecretKeyFactory factory;
		SecretKey secret = null;
		try {
			factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
			KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
			SecretKey tmp = factory.generateSecret(spec);
			secret = new SecretKeySpec(tmp.getEncoded(), "AES");
			return secret;
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (InvalidKeySpecException e) {
			e.printStackTrace();
		}
		password = null;
		return secret;
	}
	
	 // only derive the password and return a byte-array with the hash
	  public static byte[] buildSecretBytes(char[] password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
	    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
	    KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
	    SecretKey tmp = factory.generateSecret(spec);
	    return tmp.getEncoded();
	  }

	public static EncryptedData encrypt(char[] password, byte[] salt,
			byte[] rawdata) {
		Cipher cipher;
		try {
			cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
			cipher.init(Cipher.ENCRYPT_MODE, buildSecret(password, salt));
			AlgorithmParameters params = cipher.getParameters();
			byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
			byte[] ciphertext = cipher.doFinal(rawdata);
			//byte[] someData = cipher.update(rawdata);
			//byte[] moreData = cipher.doFinal();
			//byte[] combined = new byte[someData.length + moreData.length];
			//System.arraycopy(someData, 0, combined, 0, someData.length);
			//System.arraycopy(moreData, 0, combined, someData.length,moreData.length);
			//return new EncryptedData(iv, ciphertext);
			return new EncryptedData(iv, ciphertext);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		} catch (InvalidParameterSpecException e) {
			e.printStackTrace();
		}
		return new EncryptedData(new byte[0], new byte[0]);
	}

	public static byte[] decrypt(char[] password, byte[] salt,
			EncryptedData encdata) {
		Cipher cipher;
		// Decrypt the message, given derived key and initialization vector.
		try {
			cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
			cipher.init(Cipher.DECRYPT_MODE, buildSecret(password, salt),
					new IvParameterSpec(encdata.getIV()));
			byte[] decData = new byte[encdata.getEncData().length];
			decData = cipher.doFinal(encdata.getEncData());
			return decData;
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (InvalidAlgorithmParameterException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}

		return new byte[0];
	}

	public static char[] bbCharPw(char[] input) {
		for (int i = 0; i < input.length; i++) {
			input[i] = '*';
		}
		return input;
	}
	/*
	 * public static void main(String[] args) { //String bla = new
	 * String("test"); User user = new User("test", "test"); Users users = new
	 * Users(); users.add(user);
	 * System.out.println("This is the data:"+users.getList()); EncryptedData ed
	 * = encrypt("test".toCharArray(), user.getSalt(),
	 * Bytehandler.pluginDataToBytes(users));
	 * System.out.println("This is the encrypted data:"+ed); Users users2 =
	 * (Users) Bytehandler.BytesToPlugindata(decrypt("test".toCharArray(),
	 * user.getSalt(), ed)); System.out.println(users2.getList()); }
	 */
}